<template>
<div>
  <pre v-show="devmode">
    numResults:  {{numResults}}
    numFiltered: {{numFiltered}}
    offset:      {{offset}}
  </pre>
  <div v-if="timerRunning" class="loader"></div>
  <br>
  <div v-if="hasDataArray">
    <button type="button"
            :class="btnClass"
            v-on:click="prevPage()">Prev</button>
    <button type="button"
            :class="btnClass"
            v-on:click="nextPage()">Next</button>
    <span>&nbsp;Page {{currentFiltered}}/{{sizeFiltered}}&nbsp;</span>
    <button type="button"
            class="btn"
            :class="{'btn-success':filterAnd,'btn-default':!filterAnd}"
            v-on:click="toggleFilterAnd()">{{filterAnd ? 'Requiring All' : 'Matching Any'}}</button>
    <ul class="filterRow">
      <li v-for="current in subSearch"
          v-bind:key="current">
        <button type="button"
                class="btn"
                :class="{'btn-success':filterElements.includes(current),'btn-default':!filterElements.includes(current)}"
                v-on:click="toggleFilter(current)">
          {{current}}</button>
      </li>
    </ul>
    <hr>
    <ul>
      <li v-for="current in output"
          v-bind:key="current.value"
          :value="current.value">
        <button type="button"
                :class="btnClass"
                v-on:click="selectItem({name:current.label,id:current.value})">
          {{current.label}}</button>
      </li>
    </ul>
  </div>
  <div v-else-if="hasDataObject">
    <ul>
      <li :value="output.value">
        <button type="button"
                :class="btnClass"
                v-on:click="selectItem({name:output.label,id:output.value})">
          {{output.label}}</button>
      </li>
    </ul>
  </div>
</div>
</template>

<script>
export default {
    name: "Autocomplete",
    props: [
        "devmode",
        "endpoint",
        "limit",
        "search",
    ],
    data: function() {
        return {
            btnClass: 'btn btn-primary',
            bucket: '',
            filterAnd: true,
            filterElements: [],
            hasVal: false,
            offset: 0,
            output: '',
            subStringMax: 6,
            timer: 0,
            timerRunning: false,
        }
    },
    computed: {
        subSearch() { return this.search.split(' ', this.subStringMax) },
        hasDataArray() { return this.bucket && this.bucket[0] && this.bucket[0].value },
        hasDataObject() { return this.bucket && this.bucket.length > 0 },
        numResults: function() {
            return this.bucket && this.bucket.length > 0 ? this.bucket.length : 0
        },
        numFiltered() { return this.getRange.length },
        rangeBeg: function() {
            return this.offset * this.limit
        },
        rangeEnd: function() {
            return this.rangeBeg + this.limit
        },
        getRange: function() {
            return (this.bucket && this.bucket[0]) ? (this.filterAnd)
                ? this.bucket.filter(
                    item => this.subSearch.every(elem =>
                                                 (item.label.toLowerCase().indexOf(elem.toLowerCase()) > -1)
                                                 || ((item.value + '').toLowerCase().indexOf(elem.toLowerCase()) > -1))
                )
                : this.bucket.filter(
                    item => !this.filterElements
                        || this.filterElements.length < 1
                        || this.filterElements.some(elem =>
                                                    (item.label.toLowerCase().indexOf(elem.toLowerCase()) > -1)
                                                    || ((item.value + '').toLowerCase().indexOf(elem.toLowerCase()) > -1)))
                : this.bucket
        },
        sizeFiltered: function() {
            return Math.floor(this.numFiltered / this.limit) + (((this.numFiltered % this.limit) > 0) ? 1 : 0)
        },
        currentFiltered: function() {
            return this.offset + 1
        },
        frequency: () => 451,
    },
    methods: {
        toggleFilterAnd: function() {
            this.filterAnd = !this.filterAnd
        },
        toggleFilter: function(foo) {
            let filterVal = foo + ''
            if (this.filterElements.includes(filterVal)) {
                this.filterElements = this.filterElements.filter(word => word !== filterVal)
            } else {
                this.filterElements.push(filterVal)
            }
        },
        prevPage: function()
        {
            if (this.offset > 0) {
                --this.offset;
            }
        },
        nextPage: function()
        {
            if (this.currentFiltered < this.sizeFiltered) {
                ++this.offset;
            }
        },
        selectItem: function(item) {
            this.$emit('response', item)
        },
        updateOutput: function() {
            this.output
                = (this.bucket && this.bucket[0])
                ? this.getRange.slice(this.rangeBeg, this.rangeEnd)
                : this.bucket
        },
        getData: function() {
            this.hasVal = this.search !== ''
            this.timerRunning = this.hasVal
            clearTimeout(this.timer)
            this.timer = setTimeout(function() {
                if (this.endpoint) {
                    if (this.hasVal) {
                        fetch(`${this.endpoint}${this.search}`)
                            .then(response => response.json())
                            .then(json => {
                                if (json) {
                                    //NOTE: hack to make sure we only emit to parent when necessary.
                                    this.bucket = this.hasVal ? json : ''
                                } else {
                                    this.bucket = "Response failed."
                                }
                            })
                            .catch(error => {
                                this.bucket = `Request failed. ${error}`
                            })
                    } else {
                        this.bucket = ''
                    }
                } else {
                    this.bucket = "No configuration."
                }
            }.bind(this), this.frequency);
        }
    },
    watch: {
        search() {
            this.offset = 0
            this.getData()
        },
        bucket() {
            this.offset = 0
            this.filterElements = []
            this.updateOutput()
            this.timerRunning = false
            // console.error(this.timer)
        },
        filterAnd() {
            this.offset = 0
            this.filterElements = []
            this.updateOutput()
        },
        filterElements() {
            this.offset = 0
            this.updateOutput()
        },
        offset() {
            this.updateOutput()
        }
    }
}
</script>

<style scoped>
ul {
    list-style-type: none;
}
li button {
    margin-top: 2px;
    margin-bottom: 2px;
}
ul.filterRow li {
    display: inline;
}
.loader {
  border: 2px solid #f0f0ff;
  border-radius: 50%;
  border-top: 2px solid #3333ee;
  border-bottom: 2px solid #3333ee;
  width: 26px;
  height: 26px;
  -webkit-animation: spin 2s linear infinite; /* Safari */
  animation: spin 2s linear infinite;
  margin-top: 4px;
}

/* Safari */
@-webkit-keyframes spin {
  0% { -webkit-transform: rotate(0deg); }
  100% { -webkit-transform: rotate(360deg); }
}

@keyframes spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}
</style>
